/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.pivotcontrib.demos.tiles;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;

import org.apache.pivot.collections.HashSet;
import org.apache.pivot.collections.Map;
import org.apache.pivot.wtk.Application;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.ComponentMouseListener;
import org.apache.pivot.wtk.ComponentMouseButtonListener;
import org.apache.pivot.wtk.Container;
import org.apache.pivot.wtk.ContainerMouseListener;
import org.apache.pivot.wtk.DesktopApplicationContext;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.Frame;
import org.apache.pivot.wtk.HorizontalAlignment;
import org.apache.pivot.wtk.Mouse;
import org.apache.pivot.wtk.Panel;
import org.apache.pivot.wtk.Point;
import org.apache.pivot.wtk.VerticalAlignment;
import org.apache.pivot.wtk.Visual;
import org.apache.pivot.wtk.Window;
import org.apache.pivot.wtk.effects.Decorator;
import org.apache.pivot.wtk.effects.TagDecorator;
import org.apache.pivot.wtkx.WTKX;
import org.apache.pivot.wtkx.WTKXSerializer;

import org.pivotcontrib.components.TilePane;

public class TilePaneDemo implements Application {
    /*
    private class InsertionPointDecorator implements Decorator {
        private Graphics2D graphics = null;

        private static final int DIAMETER = 10;

        @Override
        public Graphics2D prepare(Component component, Graphics2D graphics) {
            this.graphics = graphics;
            return graphics;
        }

        @Override
        public void update() {
            TilePane tilePane = (TilePane)getComponent();
            TilePane.TileSequence tiles = tilePane.getTiles();

            int[] heights = new int[getMaximumColumn() + 1];

            HashSet<Point> points = new HashSet<Point>();

            graphics.setColor(Color.RED);

            for (int i = 0; i <= heights.length; i++) {
                points.add(new Point(i * (COLUMN_WIDTH + horizontalSpacing), 0));
            }

            for (int index = 0, n = tiles.getLength(); index < n; index++) {
                TilePane.Tile tile = tiles.get(index);
                int column = tile.getColumn();
                Component component = tile.getComponent();

                int columnSpan = TilePane.getColumnSpan(component);
                int y = 0;

                // Calculate the y that is needed to avoid intersection
                for (int i = 0; i < columnSpan; i++) {
                    y = Math.max(y, heights[column + i]);
                }

                if (index == insertionIndex) {
                    graphics.fillOval(insertionColumn * (COLUMN_WIDTH + horizontalSpacing) -
                        2 * DIAMETER, y - 2 * DIAMETER, 4 * DIAMETER, 4 * DIAMETER);
                }

                // Update the heights array
                for (int i = 0; i < columnSpan; i++) {
                    Point point = new Point((column + i) * (COLUMN_WIDTH + horizontalSpacing),
                        y + component.getHeight() + verticalSpacing);

                    heights[column + i] = point.y;
                    points.add(point);
                }
            }

            for (Point point : points) {
                graphics.fillOval(point.x, point.y - verticalSpacing / 2, DIAMETER, DIAMETER);
            }

            graphics = null;
        }

        @Override
        public Bounds getBounds(Component component) {
            return new Bounds(0, 0, component.getWidth() + horizontalSpacing + (DIAMETER / 2),
                component.getHeight() + verticalSpacing + (DIAMETER / 2));
        }

        @Override
        public AffineTransform getTransform(Component component) {
            return new AffineTransform();
        }
    }
    */

    private Window window = null;

    //private InsertionPointDecorator insertionPointDecorator = new InsertionPointDecorator();

    @WTKX public TilePane tilePane;

    @Override
    public void startup(Display display, Map<String, String> properties) throws Exception {
        WTKXSerializer wtkxSerializer = new WTKXSerializer();
        window = (Window)wtkxSerializer.readObject(this, "tile_pane_demo.wtkx");
        wtkxSerializer.bind(this);

        tilePane.getContainerMouseListeners().add(new ContainerMouseListener.Adapter() {
            private int insertionColumn = -1;
            private int insertionIndex = -1;

            private Point offset = null;
            private TilePane.Tile tile = null;
            private Component component = null;
            private Window window = null;

            @Override
            public boolean mouseMove(Container container, int x, int y) {
                if (offset != null
                    && Mouse.getCapturer() != container) {
                    Mouse.capture(container);

                    // Remove the tile from the tile pane
                    tilePane.getTiles().remove(tile);

                    // Place the component in a free-floating window
                    window = new Window(component);
                    window.setPreferredSize(component.getWidth(), component.getHeight());
                    window.open(TilePaneDemo.this.window);
                    component.setLocation(0, 0);

                    window.getDecorators().add(new TagDecorator(new Visual() {
                        @Override
                        public int getWidth() {
                            return 16;
                        }

                        @Override
                        public int getHeight() {
                            return 16;
                        }

                        @Override
                        public int getBaseline() {
                            return -1;
                        }

                        @Override
                        public void paint(Graphics2D graphics) {
                            graphics.setColor(Color.RED);
                            graphics.drawOval(0, 0, 16, 16);

                            graphics.translate(8, 8);
                            int h = (int)(8d / Math.sqrt(2));
                            graphics.drawLine(-h, -h, h, h);
                            graphics.drawLine(-h, h, h, -h);
                        }
                    }, HorizontalAlignment.LEFT, VerticalAlignment.TOP, -8, -8));

                    // TODO Add decorator
                }

                if (Mouse.getCapturer() == container) {
                    Display display = window.getDisplay();
                    Point point = container.mapPointToAncestor(display, x, y);
                    window.setLocation(point.x - offset.x, point.y - offset.y);

                    TilePane tilePane = (TilePane)container;
                    int columnSpan = TilePane.getColumnSpan(component);
                    insertionColumn = tilePane.getInsertionColumn(x - offset.x);
                    insertionIndex = tilePane.getInsertionIndex(insertionColumn, y - offset.y,
                        columnSpan);
                }

                return false;
            }

            @Override
            public boolean mouseDown(Container container, Mouse.Button button, int x, int y) {
                if (button == Mouse.Button.LEFT) {
                    tile = tilePane.getTileAt(x, y);

                    if (tile != null) {
                        component = tile.getComponent();
                        offset = new Point(x - component.getX(), y - component.getY());
                    }
                }

                return false;
            }

            @Override
            public boolean mouseUp(Container container, Mouse.Button button, int x, int y) {
                if (button == Mouse.Button.LEFT) {
                    if (Mouse.getCapturer() == container) {
                        Mouse.release();

                        // Remove the component from the window, and close the window
                        window.setContent(null);
                        window.close();

                        // Insert a new tile in the appropriate place
                        TilePane tilePane = (TilePane)container;
                        TilePane.Tile tile = new TilePane.Tile(component, insertionColumn);
                        tilePane.getTiles().insert(tile, insertionIndex);

                        // TODO Remove decorator
                    }

                    offset = null;
                    tile = null;
                    component = null;
                    window = null;
                }

                return false;
            }
        });

        window.open(display);
    }

    @Override
    public boolean shutdown(boolean optional) {
        if (window != null) {
            window.close();
        }

        return false;
    }

    @Override
    public void suspend() {
    }

    @Override
    public void resume() {
    }

    public static void main(String[] args) {
        DesktopApplicationContext.main(TilePaneDemo.class, args);
    }
}
